import unit.*;

import java.io.*;
import java.util.ArrayList;
import java.util.Map;

public class Compiler {
    private static ArrayList<Word> wordList = new ArrayList<>();
    private static ArrayList<Part> partList = new ArrayList<>();
    private static ArrayList<Quaternion> quaternionList = new ArrayList<>();
    private static ArrayList<String> mipsList = new ArrayList<>();
    private static ArrayList<Pair<Integer, String>> errorList = new ArrayList<>();

    public static void main(String[] args) throws IOException {
        String codeFile = "testfile.txt";
        String outputFile = "output.txt";
        String tmpCodeFile = "20373255.txt";
        String mipsFile = "mips.txt";
        String errorFile = "error.txt";

        compileCode(codeFile);
        writeOutput(outputFile);
        writeError(errorFile);
        writeTmpCode(tmpCodeFile);
        writeMips(mipsFile);
    }

    private static void compileCode(String codeFile) {
        ArrayList<String> content = new ArrayList<>();
        try {
            content = getContent(codeFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        Lexer.getInstance().lexerStart(content);
        wordList = Lexer.getInstance().getWordList();

        Parser.getInstance().parserStart(wordList);
        partList = Parser.getInstance().getPartList();

        Node root = Parser.getInstance().getRoot();
        errorList = Parser.getInstance().getErrorList();

        //search(root, 0);

        Analysis.getInstance().analysisStart(root, wordList);
        quaternionList = Analysis.getInstance().getQuaternionList();
        Map<String, Integer> twoDTable = Analysis.getInstance().getTwoDTable();
        ArrayList<Pair<Integer, String>> errorList2 = Analysis.getInstance().getErrorList();
        mergeErrors(errorList2);

        Translate.getInstance().translateStart(quaternionList, twoDTable);
        mipsList = Translate.getInstance().getMipsList();
    }

    private static void mergeErrors(ArrayList<Pair<Integer, String>> errorList2) {
        if (errorList.size() == 0) {
            errorList = errorList2;
            return;
        }
        for (int i = 0; i < errorList2.size(); i++) {
            Pair<Integer, String> pair = errorList2.get(i);
            for (int j = 0; j < errorList.size(); j++) {
                if (errorList.get(j).getOne() > pair.getOne()) {
                    errorList.add(j, pair);
                    break;
                }
                if (j == errorList.size() - 1) {
                    errorList.add(pair);
                    break;
                }
            }
        }
    }


    private static void search(Node node, int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("\t");
        }
        System.out.print(node.getIndex() + "   " + node.getType() + "\n");
        ArrayList<Node> children = node.getChildren();
        if (children.size() != 0) {
            for (int i = 0; i < depth; i++) {
                System.out.print("\t");
            }
            System.out.print(node.getType() + " 's children:\n");
        }
        for (int i = 0; i < children.size(); i++) {
            search(children.get(i), depth + 1);
        }
    }

    private static void writeOutput(String outputFile) throws IOException {
        File file = new File(outputFile);
        if (!file.exists()) {
            file.createNewFile();
        }
        FileWriter fileWriter = new FileWriter(file.getName());
        int index = 0;
        for (int i = 0; i < wordList.size(); i++) {
            fileWriter.write(i + ": " + wordList.get(i).getType() + " " + wordList.get(i).getMe() + "\n");
            while (index < partList.size() && partList.get(index).getIndex() == i) {
                fileWriter.write("<" + partList.get(index).getMe() + ">\n");
                index += 1;
            }
        }
        fileWriter.close();
    }

    private static void writeTmpCode(String tmpCodeFile) throws IOException {
        File file = new File(tmpCodeFile);
        if (!file.exists()) {
            file.createNewFile();
        }
        FileWriter fileWriter = new FileWriter(file.getName());
        for (int i = 0; i < quaternionList.size(); i++) {
            fileWriter.write(quaternionList.get(i).getPrint());
        }
        fileWriter.close();
    }

    private static void writeMips(String mipsFile) throws IOException {
        File file = new File(mipsFile);
        if (!file.exists()) {
            file.createNewFile();
        }
        FileWriter fileWriter = new FileWriter(file.getName());
        //fileWriter.write("mips code");
        for (int i = 0; i < mipsList.size(); i++) {
            fileWriter.write(mipsList.get(i) + "\n");
        }
        fileWriter.close();
    }

    private static void writeError(String errorFile) throws IOException {
        File file = new File(errorFile);
        FileWriter fileWriter = new FileWriter(file.getName());
        //fileWriter.write("error");
        for (int i = 0; i < errorList.size(); i++) {
            fileWriter.write(errorList.get(i).getOne() + " " + errorList.get(i).getTwo() + "\n");
        }
        fileWriter.close();
    }

    private static ArrayList<String> getContent(String file) throws IOException {
        ArrayList<String> content = new ArrayList<>();
        BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
        String line;
        while ((line = bufferedReader.readLine()) != null) {
            line = line.trim();
            content.add(line);
        }
        return content;
    }

}
